frontend/pages/e/[uuid].tsx (view raw)
1import {useState, useReducer, useEffect} from 'react';
2import {useTranslation} from 'react-i18next';
3import Layout from '../../layouts/Default';
4import Fab from '../../containers/Fab';
5import CarColumns from '../../containers/CarColumns';
6import NewCarDialog from '../../containers/NewCarDialog';
7import AddToMyEventDialog from '../../containers/AddToMyEventDialog';
8import EventBar from '../../containers/EventBar';
9import useToastStore from '../../stores/useToastStore';
10import {initializeApollo} from '../../lib/apolloClient';
11import ErrorPage from '../_error';
12import {
13 useUpdateEventMutation,
14 Event as EventType,
15 useEventByUuidQuery,
16 EventByUuidDocument,
17} from '../../generated/graphql';
18import useEventStore from '../../stores/useEventStore';
19import Loading from '../../containers/Loading';
20
21const POLL_INTERVAL = 10000;
22
23interface Props {
24 event: EventType;
25 eventUUID: string;
26}
27
28const EventPage = props => {
29 const {event} = props;
30 const {t} = useTranslation();
31
32 if (!event) return <ErrorPage statusCode={404} title={t`event.not_found`} />;
33
34 return <Event {...props} />;
35};
36
37const Event = (props: Props) => {
38 const {eventUUID} = props;
39 const {t} = useTranslation();
40 const addToast = useToastStore(s => s.addToast);
41 const setEvent = useEventStore(s => s.setEvent);
42 const eventUpdate = useEventStore(s => s.event);
43 const setIsEditing = useEventStore(s => s.setIsEditing);
44 const [updateEvent] = useUpdateEventMutation();
45 const [isAddToMyEvent, setIsAddToMyEvent] = useState(false);
46 const [openNewCar, toggleNewCar] = useReducer(i => !i, false);
47 const {data: {eventByUUID: event} = {}} = useEventByUuidQuery({
48 pollInterval: POLL_INTERVAL,
49 variables: {uuid: eventUUID},
50 });
51
52 useEffect(() => {
53 if (event) setEvent(event as EventType);
54 }, [event]);
55
56 const onSave = async e => {
57 try {
58 const {uuid, ...data} = eventUpdate;
59 delete data.id;
60 delete data.__typename;
61 delete data.cars;
62 delete data.waitingList;
63 await updateEvent({
64 variables: {uuid, eventUpdate: data},
65 refetchQueries: ['eventByUUID'],
66 });
67 setIsEditing(false);
68 } catch (error) {
69 console.error(error);
70 addToast(t('event.errors.cant_update'));
71 }
72 };
73
74 const onShare = async () => {
75 if (!event) return null;
76 // If navigator as share capability
77 if (!!navigator.share)
78 return await navigator.share({
79 title: `Caroster ${event.name}`,
80 url: `${window.location.href}`,
81 });
82 // Else copy URL in clipboard
83 else if (!!navigator.clipboard) {
84 await navigator.clipboard.writeText(window.location.href);
85 addToast(t('event.actions.copied'));
86 return true;
87 }
88 };
89
90 if (!event) return <Loading />;
91
92 return (
93 <Layout
94 pageTitle={t('event.title', {title: event.name})}
95 menuTitle={t('event.title', {title: event.name})}
96 displayMenu={false}
97 >
98 <EventBar
99 event={event}
100 onAdd={setIsAddToMyEvent}
101 onSave={onSave}
102 onShare={onShare}
103 />
104 <CarColumns toggleNewCar={toggleNewCar} />
105 <Fab onClick={toggleNewCar} open={openNewCar} aria-label="add-car" />
106 <NewCarDialog open={openNewCar} toggle={toggleNewCar} />
107 <AddToMyEventDialog
108 event={event}
109 open={isAddToMyEvent}
110 onClose={() => setIsAddToMyEvent(false)}
111 />
112 </Layout>
113 );
114};
115
116export async function getServerSideProps(ctx) {
117 const {uuid} = ctx.query;
118 const apolloClient = initializeApollo();
119 const {data = {}} = await apolloClient.query({
120 query: EventByUuidDocument,
121 variables: {uuid},
122 });
123 const {eventByUUID: event} = data;
124 const {host = ''} = ctx.req.headers;
125
126 return {
127 props: {
128 event,
129 eventUUID: uuid,
130 metas: {
131 title: event?.name || '',
132 url: `https://${host}${ctx.resolvedUrl}`,
133 },
134 },
135 };
136}
137
138export default EventPage;